package com.example.dmweb;

import com.alibaba.fastjson.JSON;
import com.example.dmcommom.*;
import com.example.dmdomain.UserRepository;
import com.example.dmdomain.entity.User;
import com.example.dmservice.exceloutput.service.HttpClient;
import com.example.dmservice.exceloutput.service.UserService;
import com.example.dmservice.exceloutput.service.WechatConfig;
import com.example.dmweb.Intelligentcabinet.model.CheckLoginResponse;
import com.example.dmweb.Intelligentcabinet.model.LoginResponse;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.*;

import javax.net.ssl.HttpsURLConnection;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;

import static com.example.dmservice.exceloutput.service.HttpClient.sendPost;
import static com.example.dmservice.exceloutput.service.WechatConfig.MESSAGE_TEMPLATE_ID;

@RestController
@RequestMapping("/user")
@CrossOrigin
@Api(value = "登录", tags = {"登录"})
@Slf4j
public class UserStatusController {

    @Autowired
    private UserService userService;

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private RedisTemplate<String,String> redisTemplate;

    /**
     * 自定义token, 用作生成签名,从而验证安全性
     */
    private static final String TOKEN = "DamaoWxToken";

    @PostMapping("/register")
    @NoAuthInterception
    public ResponseResult<LoginResponse> register(@RequestParam("phone") String phone, @RequestParam("smsCode") String smsCode, HttpServletRequest request) throws ParseException {

        if (StringUtils.isEmpty(phone)) {
            return ResponseResult.error("手机号不能为空");
        }
        if (StringUtils.isEmpty(smsCode)) {
            return ResponseResult.error("验证码不能为空");
        }

        LoginResponse loginResponse = new LoginResponse();
        String ip = request.getRemoteAddr();
        String token = userService.register(phone, smsCode, ip);
        if (token.equals("用户不存在")) {
            return ResponseResult.error("用户不存在");
        }
        if (token.equals("短信验证码不存在或已过期")) {
            return ResponseResult.error("短信验证码不存在或已过期");
        }
        if (token.equals("短信验证码错误")) {
            return ResponseResult.error("短信验证码错误");
        }
        loginResponse.setToken(token);
        return ResponseResult.success(loginResponse);
    }

    @PostMapping("/getSmsCode")
    @NoAuthInterception
    public ResponseResult<LoginResponse> getSmsVerifyCode(@RequestParam("phone") String phone) throws Exception {
        if (StringUtils.isEmpty(phone)) {
            return ResponseResult.error("手机号不能为空");
        }
        String smsCode = userService.getSmsCode(phone);
        if (smsCode.equals("操作过于频繁，请一分钟之后再次点击发送")) {
            return ResponseResult.error("操作过于频繁，请一分钟之后再次点击发送");
        } else {
            return ResponseResult.success();
        }
    }

    @PostMapping("/logOut")
    @NoAuthInterception
    public ResponseResult Logout(@RequestBody Map<String, String> map, HttpServletRequest request) throws ParseException {
        if (map.get("bindStatus").equals("true")) {
            return userService.logOut(map.get("value").toString(), request);
        } else {
            return ResponseResult.success("退出成功");
        }
    }

    @PostMapping("/bindPhone")
    @Deprecated
    public ResponseResult<Map<String,String>> bindPhone(@RequestParam("phone") String phone, @RequestParam("openId") String openId, @RequestParam("smsCode") String smsCode) throws ParseException {
        //先校验验证码是否正确
        String smsCodeKey = "login:verify_code:" + phone;
        String verifyCode = redisTemplate.opsForValue().get(smsCodeKey);
        if (StringUtils.isEmpty(verifyCode)) {
            return ResponseResult.error("短信验证码不存在或已过期");
        }
        if (!smsCode.equals(verifyCode)) {
            return ResponseResult.error("短信验证码错误");
        }
        //清理验证码
        if (Boolean.TRUE.equals(redisTemplate.hasKey(smsCodeKey))) {
            redisTemplate.delete(smsCodeKey);
        }
        User loginUser = userRepository.findUsersByPhone(phone);

        if (loginUser == null) {
            userService.doRegisterNoAuth(phone);
        }
        //根据手机号查找账号并修改openId
        userRepository.updateLogOpenId(phone, openId);
        User user = userRepository.findUsersByPhone(phone);

        Map<String, String> map = new HashMap<>();
        map.put("phone", phone);
        map.put("token", user.getUserId());
        return ResponseResult.success(map);
    }

    /**
     * 生成带参数的二维码，扫描关注微信公众号，自动登录网站
     * @param modelMap
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/wechat/login")
    @ResponseBody
    public ResponseResult<LoginResponse> wechatMpLogin(ModelMap modelMap) throws Exception {
//        String accessToken = wechatService.getAccessToken();
        LoginResponse loginResponse = new LoginResponse();
        String scene_str = "perFei." + new Date().getTime();
        String ticket = userService.createTempStrTicket("6000", scene_str);
        if(ticket != null){
            String qrcodeUrl = userService.showqrcode(ticket);
//            modelMap.put("qrcodeUrl", qrcodeUrl); //二维码的图片路径
            loginResponse.setQrcodeUrl(qrcodeUrl);
            loginResponse.setTicket(ticket);
        }
//        modelMap.put("scene_str", scene_str);
        loginResponse.setSceneStr(scene_str);
        return ResponseResult.success(loginResponse);
    }


    /**
     * 检测登录
     * @param scene_str
     * @return
     */
    @PostMapping("/wechat/checkLogin")
    @ResponseBody
    public ResponseResult<CheckLoginResponse> wechatMpCheckLogin(String scene_str) {
        // 根据scene_str查询数据库，获取对应记录
        log.info("-------------scene_str-------------");
        log.info(scene_str);
        CheckLoginResponse checkLoginResponse = new CheckLoginResponse();
        try {
            String openId = redisTemplate.opsForValue().get(scene_str);
            if (openId != null && !openId.isEmpty()) {
                checkLoginResponse.setResult(true);
//                checkLoginResponse.setOpenId(openId);
                checkLoginResponse.setAccount("wechat_" + openId.substring(0, 6));
                redisTemplate.delete(scene_str);
                //根据openId去查数据库中有没有绑定手机号，如果有返回手机号
                User user = userRepository.findUsersByOpenId(openId);
                if (user != null) {
                    if (user.getPhone() != null) {
                        checkLoginResponse.setPhone(user.getPhone());
                    }
                    checkLoginResponse.setOpenId(user.getUserId());
                } else {
                    User user1 = new User();

                    user1.setUserId(UUID.randomUUID().toString());
                    user1.setRegisterType("微信扫码登录");

                    String defaultPassword = "123456";
                    String md5Pwd = IdGenerator.md5Id(defaultPassword);
                    user1.setPassword(md5Pwd);

                    Date day = new Date();
                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                    sdf.setTimeZone(TimeZone.getTimeZone("GMT+8"));
                    String time = sdf.format(day);
                    user1.setCreateTime(sdf.parse(time));

                    user1.setOpenId(openId);
                    userRepository.save(user1);
                    checkLoginResponse.setOpenId(user1.getUserId());
                }
                return ResponseResult.success(checkLoginResponse);
            }
        } catch (Exception e) {
            log.error("扫码登录失败", e);
        }
        checkLoginResponse.setResult(false);
        return ResponseResult.success(checkLoginResponse);
    }

    /**
     *
     * @param httpServletRequest
     * @param requestBody
     * @return
     * @throws Exception
     */
    @PostMapping(value = "/wechat/callback")
    public String api(HttpServletRequest httpServletRequest, @RequestBody String requestBody) throws Exception {
        log.info("---------微信回调参数----------");
        log.info(requestBody);
        Map<String, String> map = readStringXmlOut(requestBody);
        //然后将EventKey和FromUserName保存在redis中
        if (map.get("Event").equals("SCAN")) {
            redisTemplate.opsForValue().set(map.get("EventKey"), map.get("FromUserName"), 60 * 3, TimeUnit.SECONDS);
            log.info("---------保存在redis---------");
            TemplateMessage templateMessage = new TemplateMessage();
            templateMessage.setTouser(map.get("FromUserName"));
            templateMessage.setTemplate_id(MESSAGE_TEMPLATE_ID);
            log.info("access_token==============" + getAccessToken());
            String requestUrl ="https://api.weixin.qq.com/cgi-bin/message/template/send" + "?access_token=" + getAccessToken();
            sendPost(requestUrl, JSON.toJSONString(templateMessage));
//            sendMessage(getAccessToken(), templateMessage);
        }
        if (map.get("Event").equals("subscribe")) {
            String key = map.get("EventKey").substring(8);
            log.info("========>>redisKey = " + key);
            redisTemplate.opsForValue().set(key, map.get("FromUserName"), 60 * 3, TimeUnit.SECONDS);
            log.info("---------保存在redis---------");
            TemplateMessage templateMessage = new TemplateMessage();
            templateMessage.setTouser(map.get("FromUserName"));
            templateMessage.setTemplate_id(MESSAGE_TEMPLATE_ID);
            log.info("access_token==============" + getAccessToken());
            String requestUrl ="https://api.weixin.qq.com/cgi-bin/message/template/send" + "?access_token=" + getAccessToken();
            sendPost(requestUrl, JSON.toJSONString(templateMessage));
        }
        return "SUCCESS";
    }

    /**
     * 回调函数 get请求 验证签名信息
     * @param request
     * @throws Exception
     */
    @GetMapping(value = "/wechat/callback")
    public void callbackGet(HttpServletRequest request, HttpServletResponse response) throws Exception{
        // TODO 验证接口配置信息
        // 接收微信服务器发送请求时传递过来的参数

        //微信加密签名，signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。
        String signature = request.getParameter("signature");
        String timestamp = request.getParameter("timestamp"); //时间戳
        String nonce = request.getParameter("nonce"); //随机数
        String echostr = request.getParameter("echostr");//随机字符串
        //将token、timestamp、nonce三个参数进行字典序排序
        //并拼接为一个字符串
        String sortStr = sort(TOKEN,timestamp,nonce);
        //字符串进行shal加密
        String mySignature = shal(sortStr);
        //校验微信服务器传递过来的签名和加密后的字符串是否一致,若一致则签名通过
        if(!"".equals(signature) && !"".equals(mySignature) && signature.equals(mySignature)){
            response.getWriter().write(echostr);
            response.getWriter().flush();
        }else {
            log.info("-----校验签名失败-----");
        }
    }

//    public String getAccessToken() throws Exception {
//        String url = WechatConfig.ACCESS_TOKEN_URL;
//        url = url.replaceAll("APPID", WechatConfig.APPID);
//        url = url.replaceAll("SECRET", WechatConfig.SECRET);
//        // 发送请求
//        HttpClient client = new HttpClient(url);
//        // 发送get请求
//        client.get();
//        // 获取到请求的结果  json格式的字符串，把json格式的字符串转换成对象或者Map集合
//        String token_content = client.getContent();
//        Map<String, Object> map = JSON.parseObject(token_content, Map.class);
//        return map.get("access_token").toString();
//    }

    public String getAccessToken() {
        String url = WechatConfig.ACCESS_TOKEN_URL;
        url = url.replaceAll("APPID", WechatConfig.APPID);
        url = url.replaceAll("SECRET", WechatConfig.SECRET);
        Map<String, Object> map = HttpClient.sendGet(url);
        return map.get("access_token").toString();
    }




    /**
     * 参数排序
     * @param token
     * @param timestamp
     * @param nonce
     * @return
     */
    public String sort(String token, String timestamp, String nonce) {
        String[] strArray = {token, timestamp, nonce};
        Arrays.sort(strArray);
        StringBuilder sb = new StringBuilder();
        for (String str : strArray) {
            sb.append(str);
        }
        return sb.toString();
    }

    /**
     * 字符串进行shal加密
     * @param str
     * @return
     */
    public String shal(String str){
        try {
            MessageDigest digest = MessageDigest.getInstance("SHA-1");
            digest.update(str.getBytes());
            byte messageDigest[] = digest.digest();

            StringBuffer hexString = new StringBuffer();
            // 字节数组转换为 十六进制 数
            for (int i = 0; i < messageDigest.length; i++) {
                String shaHex = Integer.toHexString(messageDigest[i] & 0xFF);
                if (shaHex.length() < 2) {
                    hexString.append(0);
                }
                hexString.append(shaHex);
            }
            return hexString.toString();

        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return "";
    }

    public static Map<String, String> readStringXmlOut(String xml) {
        Map<String, String> map = new HashMap<String, String>();
        Document doc = null;
        try {
            doc = DocumentHelper.parseText(xml); // 将字符串转为XML
            Element rootElt = doc.getRootElement(); // 获取根节点
            List<Element> list = rootElt.elements();//获取根节点下所有节点
            for (Element element : list) {  //遍历节点
                map.put(element.getName(), element.getText()); //节点的name为map的key，text为map的value
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return map;
    }

    /**
     * @Description 发送消息
     * @date 2023年5月29日下午4:58:02
     * @param accessToken
     * @param templateMessage
     * @return
     * @throws IOException
     */
    public static void sendMessage( String accessToken, TemplateMessage templateMessage) throws IOException {
        String requestUrl ="https://api.weixin.qq.com/cgi-bin/message/template/send" + "?access_token=" + accessToken;

        URL urlObject = new URL(requestUrl);
        HttpsURLConnection connection = (HttpsURLConnection) urlObject.openConnection();
        connection.setRequestMethod("POST");
        connection.setDoOutput(true);
        connection.setRequestProperty("Content-Type", "application/json");

        String requestBody = JSON.toJSONString(templateMessage);
        byte[] requestBodyBytes = requestBody.getBytes(StandardCharsets.UTF_8);
        connection.setRequestProperty("Content-Length", String.valueOf(requestBodyBytes.length));

        OutputStream outputStream = connection.getOutputStream();
        outputStream.write(requestBodyBytes);
        outputStream.close();

        int responseCode = connection.getResponseCode();
        BufferedReader reader;
        if (responseCode >= 200 && responseCode <= 299) {
            reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
        } else {
            reader = new BufferedReader(new InputStreamReader(connection.getErrorStream()));
        }
        StringBuilder response = new StringBuilder();
        String line;
        while ((line = reader.readLine()) != null) {
            response.append(line);
        }
        reader.close();

        connection.disconnect();
    }

}
